#ifndef UUID_11FF9B6760ED45A994715BB56E83DE19
#define UUID_11FF9B6760ED45A994715BB56E83DE19

#include "utility.hpp"
#include <memory>
#include <gvl/io/bitstream.hpp>
#include <gvl/containers/deque.hpp>
#include <gvl/list.hpp>

namespace Psync5
{

struct Section : gvl::list_node<>, NonCopyable
{
	//static int const MaxBufSize = 128;
	static int const MaxBufByteSize = 511;
	//static int const MaxBufBitSize = MaxBufByteSize * 8;

	Section(uint32_t idInit = 0)
	: id(idInit)
	, messageEnds(0)
	, partial(false)
	{
	}

	uint32_t id;

	uint8_t buffer[MaxBufByteSize + 4]; // 4 byte margin for range coder
	uint32_t messageEnds;
	
	int sizeBytes;

	bool partial;
};

struct SendSection : Section
{
	SendSection(uint32_t idInit)
	: Section(idInit)
	, lastSendMs(0)
	{
	}

	uint32_t lastSendMs;
};

struct ReceiveSection : Section
{
	ReceiveSection(uint32_t idInit)
	: Section(idInit)
	{
	}
};

struct ReceiveQueue
{
	ReceiveQueue()
	{
	}

	void reset(uint32_t nextSectionId)
	{
		frontSectionId = nextSectionId;
		queue.clear();
	}

	void addSection(std::unique_ptr<Section> section)
	{
		uint32_t id = section->id;
		uint32_t rel = (id - frontSectionId) & 0xffff;

		if(rel > 0x1000)
			return; // Ignore

		// Resize if necessary
		std::size_t size = queue.size();
		while(rel >= size)
		{
			queue.push_back(std::unique_ptr<Section>());
			++size;
		}

		std::unique_ptr<Section>& slot = queue[rel];
		if(!slot)
			slot = std::move(section);
	}

	std::unique_ptr<Section> nextSection()
	{
		if(!queue.empty())
		{
			std::unique_ptr<Section>& front = queue.front();
			if(front)
			{
				++frontSectionId;
				std::unique_ptr<Section> ret(std::move(front));
				queue.pop_front();
				return std::move(ret);
			}
		}

		return std::unique_ptr<Section>();
	}

	// ID of the first section in queue
	uint32_t frontSectionId;
	gvl::deque<std::unique_ptr<Section> > queue;
};


}

#endif // UUID_11FF9B6760ED45A994715BB56E83DE19
